/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: MinAreaCheckerTask.java
 * Written by: Daniel Schmidt
 * 
 * This code has been developed at the Karlsruhe Institute of Technology (KIT), Germany, 
 * as part of the course "Multicore Programming in Practice: Tools, Models, and Languages".
 * Contact instructor: Dr. Victor Pankratius (pankratius@ipd.uka.de)
 *
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 *
 * Electric(tm) is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Electric(tm); see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, Mass 02111-1307, USA.
 */
package com.sun.electric.plugins.minarea.mk01;

import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;

import com.sun.electric.api.minarea.ErrorLogger;
import com.sun.electric.api.minarea.LayoutCell;
import com.sun.electric.api.minarea.ManhattanOrientation;
import com.sun.electric.plugins.minarea.mk01.bitmapTraverser.BitmapTraverserHandler;
import com.sun.electric.plugins.minarea.mk01.layout.FlattenHandler;
import com.sun.electric.plugins.minarea.mk01.layout.ReduceElementsHandler;

/**
 * This object contains internal data structures and algorithms implementing a
 * single minimum area check.
 */
public class MinAreaCheckerTask {
	
	/** the forkjoinpool containing tasks for the different phases */
	private static ForkJoinPool forkjoinpool = new ForkJoinPool();

	MinAreaCheckerTask(LayoutCell topCell, long minArea, boolean reportTiles,
			ErrorLogger errorLogger) {
		
		// Phase 1
		long startPhaseOne = System.currentTimeMillis();

		// Collect all unique x and y coordinates of rectangle's edges
		ReduceElementsHandler reduceElements = new ReduceElementsHandler();

		reduceElements.start(topCell, 0, 0, ManhattanOrientation.R0);

		Set<Integer> setOfXCoordinates = reduceElements.getSetOfXCoordinates();
		Set<Integer> setOfYCoordinates = reduceElements.getSetOfYCoordinates();

		int xsize = setOfXCoordinates.size() - 1;
		int ysize = setOfYCoordinates.size() - 1;
		
		// Create two maps : 
		// 1. Map index of the bitmap to coordinate of the chip 
		// 2. Map coordinate of the chip to index of the bitmap
		int[] indexToXCoordinate = new int[xsize + 1];
		int[] indexToYCoordinate = new int[ysize + 1];
		Map<Integer, Integer> xCoordinateToIndex = new HashMap<Integer, Integer>();
		Map<Integer, Integer> yCoordinateToIndex = new HashMap<Integer, Integer>();

		Iterator<Integer> it1 = setOfXCoordinates.iterator();

		while (it1.hasNext()) {
			int x = it1.next();
			indexToXCoordinate[xCoordinateToIndex.size()] = x;
			xCoordinateToIndex.put(x, xCoordinateToIndex.size());
		}

		Iterator<Integer> it2 = setOfYCoordinates.iterator();

		while (it2.hasNext()) {
			int y = it2.next();
			indexToYCoordinate[yCoordinateToIndex.size()] = y;
			yCoordinateToIndex.put(y, yCoordinateToIndex.size());
		}

		long endPhaseOne = System.currentTimeMillis();

		if (MinAreaCheckerImplementation.DEBUG) {
			System.out.println("number of x coordinates = " + xsize);
			System.out.println(setOfXCoordinates);
			System.out.println("number of y coordinates = " + ysize);
			System.out.println(setOfYCoordinates);
		}

		// Phase 2

		long startPhaseTwo = System.currentTimeMillis();

		// initialize bitmap
		BitSet[] bitMap = new BitSet[xsize];
		for (int i = 0; i < bitMap.length; i++) {
			bitMap[i] = new BitSet();
		}

		// flatten the layout and create the bitmap
		FlattenHandler flattenLayout = new FlattenHandler(xCoordinateToIndex,
				yCoordinateToIndex, bitMap);
		flattenLayout.start(topCell, 0, 0, ManhattanOrientation.R0);

		long endPhaseTwo = System.currentTimeMillis();

		if (MinAreaCheckerImplementation.DEBUG) {
			System.out.println("BitMap: ");
			int y = 0;
			while (y < ysize) {

				for (int x = 0; x < xsize; x++) {
					char curr = bitMap[x].get(y) ? 'X' : '0';
					System.out.print(curr);
				}
				System.out.println();
				y ++;
			}
		}
		
		// Phase 3
		long startPhaseThree = System.currentTimeMillis();

		// Start the bitmap traversal and determine all polygon with size
		// less than the spcified minArea
	    BitmapTraverserHandler bitmapTraverser = new BitmapTraverserHandler(
	    		bitMap, indexToXCoordinate, indexToYCoordinate, xsize, errorLogger, minArea);
	    bitmapTraverser.start();

	    long endPhaseThree = System.currentTimeMillis();
	    
		if (MinAreaCheckerImplementation.DEBUG) {
			System.out.println("Execution time of Phase 1 : "
				+ (endPhaseOne - startPhaseOne));
			System.out.println("Execution time of Phase 2 : "
					+ (endPhaseTwo - startPhaseTwo));
			System.out.println("Execution time of Phase 3 : " 
					+ (endPhaseThree - startPhaseThree));
		}
	}
	
	/**
	 * Get the forkjoinpool that manages all tasks.
	 * 
	 * @return the forkjoinpool that manages all tasks.
	 */
	public static ForkJoinPool getForkJoinPool() {
		return forkjoinpool;
	}
}
